package com.yunc.modules.sys.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.chatbot.model.v20171011.ChatRequest;
import com.aliyuncs.chatbot.model.v20171011.ChatResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.baidu.aip.face.AipFace;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sun.management.OperatingSystemMXBean;
import com.yunc.base.controller.CommonController;
import com.yunc.common.aspect.BaseLog;
import com.yunc.common.message.Message;
import com.yunc.common.oss.QiniuCloudStorageService;
import com.yunc.common.properties.Pro;
import com.yunc.common.queue.activemq.ActiveMQSender;
import com.yunc.common.redis.RedisService;
import com.yunc.common.server.Server;
import com.yunc.common.utils.*;
import com.yunc.modules.sys.entity.*;
import com.yunc.modules.sys.entity.dto.UserOnline;
import com.yunc.modules.sys.service.*;
import eu.bitwalker.useragentutils.UserAgent;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import javax.jms.Destination;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.management.ManagementFactory;
import java.util.*;

/**
 * @author taocongcong
 * @create 2017-12-15 13:50
 */
@RestController
@RequestMapping("sysUser")
public class SysUserController extends CommonController {

    private static final Logger logger = LogManager.getLogger(SysUserController.class);

    /**
     * 用户登录次数计数  redisKey 前缀
     */
    private String SHIRO_LOGIN_COUNT = "shiro_login_count_";

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysUserTokenService sysUserTokenService;
    @Autowired
    private ISysUserRoleService sysUserRoleService;
    @Autowired
    private ISysRoleService sysRoleService;
    @Autowired
    private ISysDeptService sysDeptService;
    @Autowired
    private ISysMailRetrieveService sysMailRetrieveService;
    @Autowired
    private RedisSessionDAO redisSessionDAO;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ActiveMQSender activeMQSender;
    @Autowired
    private QiniuCloudStorageService qiniuCloudStorageService;
    @Autowired
    private Pro pro;

    @GetMapping(value = "ajaxLogin")
    public R login(SysUser sysUserInfo) {
       /* String ipStr = "111.38.169.218";
        String realAddress = AddressUtils.getRealAddressByIP(ipStr);
        System.out.print("测试地址：" + realAddress);*/
        HttpServletRequest request = ServletUtils.getRequest();
        final UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        final String ip = IPUtils.getIpAddr(request);
        // 获取客户端操作系统
        String os = userAgent.getOperatingSystem().getName();
        // 获取客户端浏览器
        String browser = userAgent.getBrowser().getName();
        // 账号不存在、密码错误
        String loginName = sysUserInfo.getLoginName();
        SysUser user = null;
        // 计算出密码
        String password = DigestUtil.md5Hex(sysUserInfo.getUserPassword());
        sysUserInfo.setUserPassword(password);
        List<SysUser> userList = sysUserService.list(new QueryWrapper<>(sysUserInfo));
        if (userList.size() != 0) {
            user = userList.get(0);
        }
        SysLoginLog loginLog = new SysLoginLog();
        loginLog.setLoginName(loginName);
        loginLog.setOs(os);
        loginLog.setBrowser(browser);
        String[] split = ip.split(",");
        String s = split[split.length - 1];
        String location = AddressUtils.getRealAddressByIP(s.trim());
        loginLog.setIpAddress(ip);
        loginLog.setLoginLocation(location);
        loginLog.setLoginTime(new Date());
        // 从此处开始计算 访问一次计数一次
        redisService.increment(SHIRO_LOGIN_COUNT + loginName, 1);
        // 此时肯定是密码错误或者其他错误,不做判断
        Integer countLogin = Integer.parseInt(redisService.get(SHIRO_LOGIN_COUNT + loginName));
        String currentDate = DateUtil.formatTime(new Date());
        String msg = "";
        if (user != null) {
            // 分情况
            if (countLogin <= 3) {
                // 登录成功 更新登录时间 last login time
                user.setLoginTime(new Date());
                sysUserService.saveOrUpdate(user);
                // 清空登录计数
                redisService.set(SHIRO_LOGIN_COUNT + loginName, "0");
                msg = user.getUserName() + "于" + currentDate + "登录系统！";
                logger.info(msg);
                // 不管是否成功，都需要记录登录日志，所以
                loginLog.setStatus(BaseConstant.SuccessErrorStatus.SUCCESS.getValue());
                loginLog.setMsg(msg);
                Message message = new Message("LOGIN_LOG_SYS", loginLog);
                redisService.rpush("LOGIN_LOG_SYS", message, 0);

                /**
                 * 测试activeMQ
                 */
                Destination destination = new ActiveMQQueue("item.queue");
                //思考如何返回给用户信息ws
                activeMQSender.sendChannelMess(destination, msg);

                Destination destinationTopic = new ActiveMQTopic("item.topic");
                activeMQSender.sendTopicChannelMess(destinationTopic, msg);
                // 创建token
                return sysUserTokenService.insertToken(user.getId());
            }
            redisService.decrBy(SHIRO_LOGIN_COUNT + loginName, 1);
            countLogin --;
            msg = "由于密码输入错误次数大于" + countLogin + "次，帐号已经禁止登录！时间:" + countLogin * 60 + "秒";
            // 不管是否成功，都需要记录登录日志，所以
            loginLog.setStatus(BaseConstant.SuccessErrorStatus.ERROR.getValue());
            loginLog.setMsg(msg);
            Message message = new Message("LOGIN_LOG_SYS", loginLog);
            redisService.rpush("LOGIN_LOG_SYS", message, 0);
            return R.error(msg);
        }
        if (countLogin < 3) {
            // 不管是否成功，都需要记录登录日志，所以
            msg = "帐号或密码不正确！";
            loginLog.setStatus(BaseConstant.SuccessErrorStatus.ERROR.getValue());
            loginLog.setMsg(msg);
            Message message = new Message("LOGIN_LOG_SYS", loginLog);
            redisService.rpush("LOGIN_LOG_SYS", message, 0);
            return R.error(msg);
        }
        // 不管是否成功，都需要记录登录日志，所以
        msg = "由于密码输入错误次数大于" + countLogin + "次，帐号已经禁止登录！时间:" + countLogin * 60 + "秒";
        loginLog.setStatus(BaseConstant.SuccessErrorStatus.ERROR.getValue());
        loginLog.setMsg(msg);
        Message message = new Message("LOGIN_LOG_SYS", loginLog);
        redisService.rpush("LOGIN_LOG_SYS", message, 0);
        redisService.expire(SHIRO_LOGIN_COUNT + loginName, 60 * countLogin);
        return R.error(msg);
    }

    @PostMapping(value = "faceLogin")
    public R faceLogin(HttpServletRequest request, HttpServletResponse response) {
        try {
            String  base = request.getParameter("base");
            /*BASE64Decoder decoder = new BASE64Decoder();
            byte[] b = decoder.decodeBuffer(base);
            for(int i=0;i<b.length;++i)
            {
                if(b[i]<0)
                {//调整异常数据
                    b[i]+=256;
                }
            }*/
            //byte[] bytes = base.getBytes();
            AipFace client = new AipFace(pro.getQFaceRecognitionAppId(), pro.getQFaceRecognitionAppKey(),
                                pro.getQFaceRecognitionSecretKey());
            HashMap<String, String> options = new HashMap<>();
            options.put("ext_fields", "faceliveness");
            options.put("user_top_num", "3");
            String groupId = "admin";
            List<String> groupList = new ArrayList<>();
            groupList.add(groupId);
            // 保存图片
           // String upload = qiniuCloudStorageService.uploadImage(b);
            org.json.JSONObject jsonObject = client.search(base, "BASE64", groupId, options);
            //boolean result = getResult(base, "http://posqrcb2e.bkt.clouddn.com/upload/20190323/0334a28dacee417cbec588b1946c6c03.jpg");
            System.out.print(jsonObject);
            if (jsonObject != null) {
                int code = jsonObject.getInt("error_code");
                if (code == 0) {
                    // 获取到userId
                    org.json.JSONObject resultObj = jsonObject.getJSONObject("result");
                    if (resultObj != null) {
                        org.json.JSONArray userListArr = resultObj.getJSONArray("user_list");
                        if (userListArr != null && userListArr.length() > 0) {
                            org.json.JSONObject o = (org.json.JSONObject)userListArr.get(0);
                            String userId = o.getString("user_id");
                            SysUser sysUserInfo = new SysUser();
                            sysUserInfo.setLoginName(userId);
                            List<SysUser> userList = sysUserService.list(new QueryWrapper<>(sysUserInfo));
                            if (userList != null && userList.size() > 0) {
                                return sysUserTokenService.insertToken(userList.get(0).getId());
                            }
                        }
                    }
                } else {
                    String errorMsg = jsonObject.getString("error_msg");
                    return R.error(errorMsg);
                }
            }
            //return R.error();
        } catch (Exception e) {
            e.printStackTrace();
            return R.error();
        }
        return R.error();
    }

    @GetMapping("/page")
    public R page(Page<SysUser> page, SysUser sysUser){
        IPage<SysUser> sysUserPage = sysUserService.pageInfo(page, sysUser);
        return R.ok().put("data", sysUserPage.getRecords()).put("count", sysUserPage.getTotal());
    }

    @GetMapping("/list")
    //@Cacheable(value = "user-list-key")
    public R list(){
        List<SysUser> sysUserList = sysUserService.list(null);
        logger.info("在" + new Date() + "查询所有用户");
        return R.ok().put("sysUserList", sysUserList);
    }

    @GetMapping("/listTree")
    public List<ZTreeNode> listTree(){
        List<ZTreeNode> deptUserList = sysUserService.listDeptUserTree();
        return deptUserList;
    }

    @GetMapping("/online")
    public R online(Page<SysUser> page){
        Collection<Session> ss = redisSessionDAO.getActiveSessions();
        List<UserOnline> list = new ArrayList<>();
        UserOnline userOnline;
        for (Session s : ss) {
            userOnline = new UserOnline();
            userOnline.setSessionId((String) s.getId());
            userOnline.setIpaddr(s.getHost());
            userOnline.setLastAccessTime(s.getLastAccessTime());
            Object obj = s.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
            if (obj != null) {
                SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
                if (spc.getPrimaryPrincipal() != null) {
                    // 转成User
                    SysUser u = (SysUser) spc.getPrimaryPrincipal();
                    userOnline.setUsername(u.getUserName());
                }
            } else {
                continue;
            }
            // 装成list，好做分页查询功能
            list.add(userOnline);
        }
        long startL = (page.getCurrent() - 1) * page.getSize();
        long endL = startL + page.getSize();
        int start = (int)startL;
        int end = (int)endL;
        List<UserOnline> records = list.subList(start, end > list.size() ? list.size() : end);
        return R.ok().put("data", records).put("count", list.size());
    }

    @GetMapping("/view")
    @Cacheable(value = "user-key",key="#userid+'view'")
    public SysUser view(String userid){
        SysUser sysUser = sysUserService.getById(userid);
        logger.info("在" + new Date() + "查询用户，id：" + userid);
        return sysUser;
    }

    @GetMapping("/userInfo")
    public R info(@RequestParam(required = false) Long userId){
        SysUser sysUser = sysUserService.getById(userId);
        // 获取用户角色
        List<SysUserRole> userRoleList = new ArrayList<>();
        if (userId != null) {
            SysUserRole roleRecord = new SysUserRole();
            roleRecord.setUserId(userId);
            QueryWrapper<SysUserRole> ew = new QueryWrapper<>(roleRecord);
            userRoleList = sysUserRoleService.list(ew);
        }
        // 获取所有角色
        SysRole record = new SysRole();
        record.setStatus("1");
        List<SysRole> sysRoleList = sysRoleService.list(new QueryWrapper<>(record));
        // 查询部门
        if (sysUser != null && StringUtils.isNotEmpty(sysUser.getDeptId())) {
            SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
            if (sysDept != null) {
                sysUser.setDeptName(sysDept.getName());
            }
        }
        return R.ok().put("sysUser", sysUser).put("sysRoleList", sysRoleList).put("userRoleList", userRoleList);
    }

    @GetMapping("/info")
    public R info(){
        SysUser sysUser = sysUserService.getById(getUserId());
        logger.info("在" + DateUtil.formatDateTime(new Date()) + "查询当前用户");
        return R.ok().put("sysUser", sysUser);
    }

    @GetMapping("/checkUnique")
    public R checkUnique(Long userId, String loginName) {
        String recordName = "";
        if (userId != null && userId != 0) {
            SysUser user = sysUserService.getById(userId);
            recordName = user.getLoginName();
        }
        QueryWrapper<SysUser> ew = new QueryWrapper<>();
        ew.eq("login_name", loginName);
        SysUser sysUser = sysUserService.getOne(ew);
        if (sysUser != null ) {
            if (StringUtils.isNotEmpty(recordName) && StringUtils.equals(loginName, recordName)) {
                return R.ok();
            }
            return R.error("您输入的登录名重复");
        }
        return R.ok();
    }

    /**
     * 保存
     */
    @BaseLog("用户管理")
    @PostMapping("/save")
    @RequiresPermissions("sys:user:save")
    @CacheEvict(value={"user-dept-tree-key"}, allEntries=true)
    public R save(@RequestBody SysUser user){
        return sysUserService.saveUser(user);
    }

    /**
     * 修改
     */
    @BaseLog("用户管理")
    @PutMapping(value = "/update")
    @RequiresPermissions("sys:user:update")
    public R update(@RequestBody SysUser user){
        Long userId = user.getId();
        boolean flag = sysUserService.updateById(user);
        if (flag) {
            // 删除权限
            SysUserRole record = new SysUserRole();
            record.setUserId(userId);
            boolean removeFlag = sysUserRoleService.remove(new QueryWrapper<>(record));
            boolean userRoleFlag = sysUserRoleService.insertList(userId, user.getRoleIds());
            if (removeFlag && userRoleFlag) {
                return R.ok();
            }
        }
        return R.error();
    }

    /**
     * 重置密码
     */
    @PutMapping(value = "/resetPassword")
    public R update(Long userId, @RequestParam(required = false) String userPassword,
                    @RequestParam(required = false) String sid){
        if (StringUtils.isNotEmpty(sid)) {
            R r = this.verifyUrl(userId, sid);
            int code = (int) r.get("code");
            if (code != 0) {
                return r;
            }
        }
        SysUser sysUser = new SysUser();
        sysUser.setId(userId);
        if (StringUtils.isEmpty(userPassword)) {
            userPassword = "123456";
        }
        sysUser.setUserPassword(DigestUtil.md5Hex(userPassword));
        boolean flag = sysUserService.updateById(sysUser);
        if (flag) {
            return R.ok();
        }
        return R.error();
    }


    /**
     * 重置邮箱密码
     */
    @PutMapping(value = "/mail/{loginName}")
    public R mail(HttpServletRequest request, @PathVariable String loginName) {
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
        return sysMailRetrieveService.saveMailRetrieve(basePath, loginName);
    }

    /**
     * 校验邮箱重置路径是否正确
     */
    @PutMapping(value = "/verifyUrl")
    public R verifyUrl(Long userId, String sid) {
        // 获取数据库中的找回密码
        return sysMailRetrieveService.verifyUrl(userId, sid);
    }

    /**
     * 聊天机器人
     */
    @PutMapping(value = "/aiChat")
    public R aiChat(String toId, String content) throws ClientException {
        DefaultProfile profile = DefaultProfile.getProfile("cn-shanghai", pro.getAliyunAccessKeyId(), pro.getAliyunAccessKeySecret());
        IAcsClient client = new DefaultAcsClient(profile);
        ChatRequest request = new ChatRequest();
        request.setInstanceId(pro.getAliyunChatbotOne());
        request.setUtterance(content);
        String message = "滚";
        try {
            ChatResponse response = client.getAcsResponse(request);
            // System.out.println(new Gson().toJson(response));
            List<ChatResponse.Message> messages = response.getMessages();
            if (messages != null && messages.size() > 0) {
                message = messages.get(0).getText().getContent();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String s = "{\"username\":\"%s\",\"avatar\":\"%s\",\"id\":\"%s\",\"type\":\"%s\",\"content\":\"%s\"}";
        String text = String.format(s, "客服姐姐", "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1736487673,2633075576&fm=26&gp=0.jpg",
                toId, "friend", message);
        return R.ok().put("text", text);
    }

    /**
     * 系统信息
     */
    @GetMapping("/systemInfo")
    public R getSystemInfo() throws Exception {
        String osName = System.getProperty("os.name");
        OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory
                .getOperatingSystemMXBean();
        double systemCpuLoad = osmxb.getSystemCpuLoad();
        int kb = 1024;
        String cpuLoad = NumberUtil.roundStr(systemCpuLoad * 100, 2);
        // 已使用的物理内存
        long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb.getFreePhysicalMemorySize()) / kb;
        long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb;
        double memory = NumberUtil.div(usedMemory, totalMemorySize);
        String memoryLoad = NumberUtil.roundStr(memory * 100, 2);

        // 整体
        Server server = new Server();
        server.copyTo();
        return R.ok().put("osName", osName).put("cpuLoad", cpuLoad)
                .put("memoryLoad", memoryLoad);
    }
}
